package poker;

import java.util.Arrays;
import java.util.Collections;
import java.util.Vector;

import poker.beans.*;

public class Evaluator {
	
	private static final int[] cardValues = {14, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
	
	public static void findBestHand(GameBean game, PlayerBean player) {
		Vector<CardBean> cards = new Vector<CardBean>();
		cards.addAll(game.getCommunityCards());
		cards.addAll(player.getCards());		
		
		for(int i = 0; i < cards.size() - 1; i++){
			for(int j = i + 1; j < cards.size(); j++){
				Vector<CardBean> sampleHand = viewHand(cards, i, j);
				int sampleHandStrength = evalHand(sampleHand);
				if( player.getStrongestHand() < sampleHandStrength ){
					player.setStrongestHand(sampleHandStrength);					
				}
			}
		}				
	}

	private static int evalHand(Vector<CardBean> cards) {
		if (hasRoyalFlush( cards )) return 1000000;
		else if (hasStraightFlush( cards )) return 900000 + highCard(cards);
		else if (hasFourOfAKind( cards )) return 800000 + addedValue(cards, "four");
		else if (hasFullHouse( cards )) return 700000 + addedValue(cards, "house");
		else if (hasFlush( cards )) return 600000 + highCard(cards);
		else if (hasStraight( cards )) return 500000 + highCard(cards);	
		else if (hasThreeOfAKind( cards )) return 400000 + addedValue(cards, "three");
		else if (hasTwoPairs( cards )) return 300000 + addedValue(cards, "2pair");
		else if (hasPair( cards )) return 200000 + addedValue(cards, "pair");
		else return highCard( cards );	
	}

	private static int addedValue(Vector<CardBean> cards, String hand) {
		Integer[] handHist = makeHist(cards);	
		if(hand.equals("house")){
			int addedHandValue = 0;
			for(int i = 0; i < handHist.length; i++){
				if(handHist[i] == 3) addedHandValue += 100 * cardValues[0];
				if(handHist[i] == 2) addedHandValue += cardValues[0];
			}
			return addedHandValue;
		}
		else if( hand == "four" ) return handValue( handHist, 10, 4 ) + evalKicker( handHist, 1 );	
		else if(hand == "three")return handValue( handHist, 100, 3 ) + evalKicker( handHist, 10 );
		else if( hand == "2pair" ) return handValue( handHist, 100, 2 ) + evalKicker( handHist, 1 );
		else if(hand == "pair") return handValue( handHist, 1000, 2 ) + evalKicker( handHist, 100 );		
		else return 0;
	}

	private static int handValue(Integer[] handHist, int multiplier, int pattern) {
		int value = 0;
		int mp = multiplier;
		if (handHist[0] == pattern){
			value += cardValues[0] * mp;
			mp /= 10;
		}
		for( int i = handHist.length - 1; i > 0; i-- ){
			if( handHist[i] == pattern ){
				if( mp < 1 ) break;
				value += cardValues[i] * mp;
				mp /= 10;
			}
		}
		return value;
	}

	private static int evalKicker(Integer[] handHist, int multiplier) {
		int kickerValue = 0;
		int mp = multiplier;
		Integer[] kickers = handHist;
		for(int i = 0; i < kickers.length; i++){
			if( kickers[i] != 1 ) kickers[i] = 0;
		}
		if(kickers[0] == 1){
			kickerValue += cardValues[0] * mp;
			mp /= 10;
		}
		for(int i = kickers.length - 1; i > 0; i--){
			if( mp < 1 ) break;
			if(kickers[i] == 1){
				kickerValue += cardValues[i] * mp;
				mp /= 10;
			}
		}		
		return kickerValue;
	}

	private static int highCard(Vector<CardBean> cards) {
		int maxValue = cardValues[0];
		Integer[] handHist = makeHist(cards);
		if (handHist[0] > 0) return maxValue;
		else {
			for (int i = cards.size() - 1; i > 0; i--){
				maxValue -= 1;
				if (handHist[i] > 0) break;
			}
		}
		return maxValue;
	}

	private static boolean hasPair(Vector<CardBean> cards) {
		Integer[] sortedHandHist = makeHist(cards);
		if (sortedHandHist[0] == 2 && sortedHandHist[1] < 2) return true;
		else return false;
	}

	private static boolean hasTwoPairs(Vector<CardBean> cards) {
		Integer[] sortedHandHist = makeHist(cards);
		if (sortedHandHist[0] == 2 && sortedHandHist[1] == 2 && sortedHandHist[2] < 2 ) return true;
		else return false;
	}

	private static boolean hasThreeOfAKind(Vector<CardBean> cards) {
		Integer[] sortedHandHist = makeHist(cards);
		if (sortedHandHist[0] == 3 && sortedHandHist[1] < 2) return true;
		else return false;
	}

	private static boolean hasStraight(Vector<CardBean> cards) {
		boolean hasStraight = true;
		Integer[] handHist = makeHist(cards);
		for(int i = 0; i < handHist.length; i++){
			if( handHist[i] != 1){
				hasStraight = false;
				break;
			}
		}	
		return hasStraight;
	}

	private static boolean hasFlush(Vector<CardBean> cards) {
		boolean hasFlush = true;
		String suit = cards.get(0).getSuit();
		for ( int i = 1; i < cards.size(); i++ ){
			if (!cards.get(i).getSuit().equals(suit)){
				hasFlush = false;
				break;
			}
		}
		return hasFlush;
	}

	private static boolean hasFullHouse(Vector<CardBean> cards) {
		Integer[] sortedHandHist = makeHist(cards);
		if (sortedHandHist[0] == 3 && sortedHandHist[1] == 2) return true;
		else return false;
	}

	private static boolean hasFourOfAKind(Vector<CardBean> cards) {
		Integer[] sortedHandHist = makeHist(cards);				
		if (sortedHandHist[0] == 4) return true;
		else return false;
	}

	private static Integer[] makeHist(Vector<CardBean> cards) {
		Integer[] hist = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		for( int i = 0; i < cards.size(); i++ ){
			if ( cards.get(i).equals("A") ) hist[0]++;
			if ( cards.get(i).equals("2") ) hist[1]++;
			if ( cards.get(i).equals("3") ) hist[2]++;
			if ( cards.get(i).equals("4") ) hist[3]++;
			if ( cards.get(i).equals("5") ) hist[4]++;
			if ( cards.get(i).equals("6") ) hist[5]++;
			if ( cards.get(i).equals("7") ) hist[6]++;
			if ( cards.get(i).equals("8") ) hist[7]++;
			if ( cards.get(i).equals("9") ) hist[8]++;
			if ( cards.get(i).equals("10") ) hist[9]++;
			if ( cards.get(i).equals("J") ) hist[10]++;
			if ( cards.get(i).equals("Q") ) hist[11]++;
			if ( cards.get(i).equals("K") ) hist[12]++;
		}
		Arrays.sort(hist, Collections.reverseOrder());
		return hist;
	}

	private static boolean hasStraightFlush(Vector<CardBean> cards) {
		if ( hasStraight( cards ) && hasFlush( cards ) ) return true;
		else return false;
	}

	private static boolean hasRoyalFlush(Vector<CardBean> cards) {
		if (hasCard( cards, "A" ) && hasCard( cards, "K" ) && hasStraightFlush( cards )) return true;
		else return false;
	}

	private static boolean hasCard(Vector<CardBean> cards, String number) {
		boolean playerHasCard = false;
		for ( int i = 0; i < cards.size(); i++ ){
			if (cards.get(i).getNumber().equals(number)){
				playerHasCard = true;
				break;
			}
		}
		return playerHasCard;
	}

	private static Vector<CardBean> viewHand(Vector<CardBean> cards, int i,	int j) {
		Vector<CardBean> hand = new Vector<CardBean>();
		for( int k = 0; k < cards.size(); k++) if( k != i && k != j ) hand.add(cards.get(k));
		return hand;
	}


}
